#pragma once 


#include <iostream>
#include <string>
#include <cstdio>
#include <set>
#include <cstring>
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace log_ns;

class Command
{
private:
public:
    Command()
    {
        _safe_command.insert("ll");
        _safe_command.insert("touch");
        _safe_command.insert("pwd");
        _safe_command.insert("whoami");
        _safe_command.insert("which");
    }

    bool SafeCheck(const std::string& cmdStr)
    {
        for (auto& cmd : _safe_command)
        {
            if (strncmp(cmd.c_str(), cmdStr.c_str(), cmd.size()) == 0)
            {
                return true;
            }
        }
        return false;
    }

    std::string Execute(const std::string& cmdStr)
    {
        // if (!SafeCheck(cmdStr)) return "unsafe";
        std::string result;
        FILE* fp = popen(cmdStr.c_str(), "r");
        if (fp)
        {
            char line[1024];
            while (fgets(line, sizeof line, fp))
            {
                result += line;
            }
            pclose(fp);
            return result.empty() ? "success" : result;
        }
        return "Execute Error";
    }

    void HandlerCommand(int sockfd, InetAddr& addr)
    {
        // 这里还是把命令执行当作长服务 
        while (true)
        {
            char cmdBuffer[1024]; // 不管什么数据，统一当作字符串读取
            ssize_t n = ::recv(sockfd, cmdBuffer, (sizeof cmdBuffer) - 1, 0);
            if (n > 0)
            {
                cmdBuffer[n] = 0;
                LOG(DEBUG, "Get command from [%s], command: %s\n", addr.GetAddrStr().c_str(), cmdBuffer);
                std::string result = Execute(cmdBuffer);
                int m = ::send(sockfd, result.c_str(), result.size(), 0);
                if (m < 0)
                {
                    LOG(ERROR, "write() -> Error, errno: %d -> %s\n", errno, strerror(errno));
                }
                else if (m == 0)
                {
                    LOG(WARNING, "write() None?\n");
                }
            }
            else if (n == 0)
            {
                // 在文件系统里表示读到文件结尾，而在网络里表示 Client 结束，想想管道
                LOG(INFO, "Client [%s] quit\n", addr.GetAddrStr().c_str());
                break;
            }
            else
            {
                LOG(ERROR, "read() -> Error, errno: %d -> %s\n", errno, strerror(errno));
                break;
            }
        }
        ::close(sockfd);
    }

    ~Command()
    {}

private:
    std::set<std::string> _safe_command;
};

